package com.myself.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author W.S.
 * @version v4.0.0
 * @description nio 服务端
 * @date Created in 2018/9/5 15:49
 */
public class NioServer {

    //选择器
    private Selector selector;

    //端口
    private final static int PORT = 8686;

    //缓存区大小容量
    private final static int BUF_SIZE = 1024;

    /**
     * 初始化服务端
     * @throws IOException
     */
    private void initNioServer() throws IOException {
        //初始化管理通道的选择器
        selector = Selector.open();
        //创建服务端通道对象
        ServerSocketChannel socketChannel = ServerSocketChannel.open();
        //设置为非阻塞
        socketChannel.configureBlocking(false);
        //绑定通道到指定的端口
        socketChannel.socket().bind(new InetSocketAddress(PORT));

        //将改通道与选择管理器绑定，向选择器注册OP_ACCEPT(接受)事件
        SelectionKey selectionKey = socketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("nioserver start:"+PORT);
    }

    /**
     * 监听
     * @throws IOException
     */
    public void listen() throws IOException{
        //轮询
        while(true){
            //这是一个阻塞方法，一直等待有事件就绪可执行，返回值是key的数量（可以有多个）
            int keyLength = selector.select();
            Set keys = selector.selectedKeys();
            Iterator iterator = keys.iterator();
            while(iterator.hasNext()){
                //得到集合中的一个key实例
                SelectionKey key = (SelectionKey)iterator.next();
                //拿到当前key实例之后记得在迭代器中将这个元素删除，非常重要，否则会出错
                iterator.remove();
                process(key);
                keys.clear();
            }
        }
    }

    public void process(SelectionKey selectionKey) throws IOException{
        ServerSocketChannel server = null;
        SocketChannel client = null;
        ByteBuffer receive = ByteBuffer.allocate(BUF_SIZE);
        ByteBuffer send = ByteBuffer.allocate(BUF_SIZE);
        if(selectionKey.isAcceptable()){
            System.out.println("服务端监听到OP_ACCEPT事件");
            server = (ServerSocketChannel) selectionKey.channel();
            client = server.accept();
            System.out.println("服务端接收成功！");
            client.configureBlocking(false);
            client.register(selector,SelectionKey.OP_READ);
        }else if(selectionKey.isReadable()){
            System.out.println("服务端监听到OP_READ事件读取客服端的消息");
            client = (SocketChannel) selectionKey.channel();
            int lenght = client.read(receive);
            if(lenght > 0){
                System.out.println("接受到客户端的消息："+new String(receive.array(),0,lenght));
                //client.register(selector,SelectionKey.OP_WRITE);
            }
        }else if(selectionKey.isWritable()){
            System.out.println("服务端监听到OP_WRITE事件 开始发送给客户端消息");
            client = (SocketChannel) selectionKey.channel();
            send.clear();
            send.put("我是发送送给客户端的消息！".getBytes());
            send.flip();
            client.write(send);
        }
    }

    public static void main(String[] args) {
        NioServer server = new NioServer();
        try {
            server.initNioServer();
            server.listen();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
